home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / g_quake / ultqsrc.zip / PR_LEX.C < prev    next >
C/C++ Source or Header  |  1996-07-25  |  13KB  |  678 lines

  1.  
  2. #include "qcc.h"
  3.  
  4. int            pr_source_line;
  5.  
  6. char        *pr_file_p;
  7. char        *pr_line_start;        // start of current source line
  8.  
  9. int            pr_bracelevel;
  10.  
  11. char        pr_token[2048];
  12. token_type_t    pr_token_type;
  13. type_t        *pr_immediate_type;
  14. eval_t        pr_immediate;
  15.  
  16. char    pr_immediate_string[2048];
  17.  
  18. int        pr_error_count;
  19.  
  20. char    *pr_punctuation[] =
  21. // longer symbols must be before a shorter partial match
  22. {"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL};
  23.  
  24. // simple types.  function types are dynamically allocated
  25. type_t    type_void = {ev_void, &def_void};
  26. type_t    type_string = {ev_string, &def_string};
  27. type_t    type_float = {ev_float, &def_float};
  28. type_t    type_vector = {ev_vector, &def_vector};
  29. type_t    type_entity = {ev_entity, &def_entity};
  30. type_t    type_field = {ev_field, &def_field};
  31. type_t    type_function = {ev_function, &def_function,NULL,&type_void};
  32. // type_function is a void() function used for state defs
  33. type_t    type_pointer = {ev_pointer, &def_pointer};
  34.  
  35. type_t    type_floatfield = {ev_field, &def_field, NULL, &type_float};
  36.  
  37. int        type_size[8] = {1,1,1,3,1,1,1,1};
  38.  
  39. def_t    def_void = {&type_void, "temp"};
  40. def_t    def_string = {&type_string, "temp"};
  41. def_t    def_float = {&type_float, "temp"};
  42. def_t    def_vector = {&type_vector, "temp"};
  43. def_t    def_entity = {&type_entity, "temp"};
  44. def_t    def_field = {&type_field, "temp"};
  45. def_t    def_function = {&type_function, "temp"};
  46. def_t    def_pointer = {&type_pointer, "temp"};
  47.  
  48. def_t    def_ret, def_parms[MAX_PARMS];
  49.  
  50. def_t    *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer};
  51.  
  52. void PR_LexWhitespace (void);
  53.  
  54.  
  55. /*
  56. ==============
  57. PR_PrintNextLine
  58. ==============
  59. */
  60. void PR_PrintNextLine (void)
  61. {
  62.     char    *t;
  63.  
  64.     printf ("%3i:",pr_source_line);
  65.     for (t=pr_line_start ; *t && *t != '\n' ; t++)
  66.         printf ("%c",*t);
  67.     printf ("\n");
  68. }
  69.  
  70. /*
  71. ==============
  72. PR_NewLine
  73.  
  74. Call at start of file and when *pr_file_p == '\n'
  75. ==============
  76. */
  77. void PR_NewLine (void)
  78. {
  79.     boolean    m;
  80.     
  81.     if (*pr_file_p == '\n')
  82.     {
  83.         pr_file_p++;
  84.         m = true;
  85.     }
  86.     else
  87.         m = false;
  88.  
  89.     pr_source_line++;
  90.     pr_line_start = pr_file_p;
  91.  
  92. //    if (pr_dumpasm)
  93. //        PR_PrintNextLine ();
  94.     if (m)
  95.         pr_file_p--;
  96. }
  97.  
  98. /*
  99. ==============
  100. PR_LexString
  101.  
  102. Parses a quoted string
  103. ==============
  104. */
  105. void PR_LexString (void)
  106. {
  107.     int        c;
  108.     int        len;
  109.     
  110.     len = 0;
  111.     pr_file_p++;
  112.     do
  113.     {
  114.         c = *pr_file_p++;
  115.         if (!c)
  116.             PR_ParseError ("EOF inside quote");
  117.         if (c=='\n')
  118.             PR_ParseError ("newline inside quote");
  119.         if (c=='\\')
  120.         {    // escape char
  121.             c = *pr_file_p++;
  122.             if (!c)
  123.                 PR_ParseError ("EOF inside quote");
  124.             if (c == 'n')
  125.                 c = '\n';
  126.             else if (c == '"')
  127.                 c = '"';
  128.             else
  129.                 PR_ParseError ("Unknown escape char");
  130.         }
  131.         else if (c=='\"')
  132.         {
  133.             pr_token[len] = 0;
  134.             pr_token_type = tt_immediate;
  135.             pr_immediate_type = &type_string;
  136.             strcpy (pr_immediate_string, pr_token);
  137.             return;
  138.         }
  139.         pr_token[len] = c;
  140.         len++;
  141.     } while (1);
  142. }
  143.  
  144. /*
  145. ==============
  146. PR_LexNumber
  147. ==============
  148. */
  149. float PR_LexNumber (void)
  150. {
  151.     int        c;
  152.     int        len;
  153.     
  154.     len = 0;
  155.     c = *pr_file_p;
  156.     do
  157.     {
  158.         pr_token[len] = c;
  159.         len++;
  160.         pr_file_p++;
  161.         c = *pr_file_p;
  162.     } while ((c >= '0' && c<= '9') || c == '.');
  163.     pr_token[len] = 0;
  164.     return atof (pr_token);
  165. }
  166.  
  167. /*
  168. ==============
  169. PR_LexVector
  170.  
  171. Parses a single quoted vector
  172. ==============
  173. */
  174. void PR_LexVector (void)
  175. {
  176.     int        i;
  177.     
  178.     pr_file_p++;
  179.     pr_token_type = tt_immediate;
  180.     pr_immediate_type = &type_vector;
  181.     for (i=0 ; i<3 ; i++)
  182.     {
  183.         pr_immediate.vector[i] = PR_LexNumber ();
  184.         PR_LexWhitespace ();
  185.     }
  186.     if (*pr_file_p != '\'')
  187.         PR_ParseError ("Bad vector");
  188.     pr_file_p++;
  189. }
  190.  
  191. /*
  192. ==============
  193. PR_LexName
  194.  
  195. Parses an identifier
  196. ==============
  197. */
  198. void PR_LexName (void)
  199. {
  200.     int        c;
  201.     int        len;
  202.     
  203.     len = 0;
  204.     c = *pr_file_p;
  205.     do
  206.     {
  207.         pr_token[len] = c;
  208.         len++;
  209.         pr_file_p++;
  210.         c = *pr_file_p;
  211.     } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' 
  212.     || (c >= '0' && c <= '9'));
  213.     pr_token[len] = 0;
  214.     pr_token_type = tt_name;
  215. }
  216.  
  217. /*
  218. ==============
  219. PR_LexPunctuation
  220. ==============
  221. */
  222. void PR_LexPunctuation (void)
  223. {
  224.     int        i;
  225.     int        len;
  226.     char    *p;
  227.     
  228.     pr_token_type = tt_punct;
  229.     
  230.     for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++)
  231.     {
  232.         len = strlen(p);
  233.         if (!strncmp(p, pr_file_p, len) )
  234.         {
  235.             strcpy (pr_token, p);
  236.             if (p[0] == '{')
  237.                 pr_bracelevel++;
  238.             else if (p[0] == '}')
  239.                 pr_bracelevel--;
  240.             pr_file_p += len;
  241.             return;
  242.         }
  243.     }
  244.     
  245.     PR_ParseError ("Unknown punctuation");
  246. }
  247.  
  248.         
  249. /*
  250. ==============
  251. PR_LexWhitespace
  252. ==============
  253. */
  254. void PR_LexWhitespace (void)
  255. {
  256.     int        c;
  257.     
  258.     while (1)
  259.     {
  260.     // skip whitespace
  261.         while ( (c = *pr_file_p) <= ' ')
  262.         {
  263.             if (c=='\n')
  264.                 PR_NewLine ();
  265.             if (c == 0)
  266.                 return;        // end of file
  267.             pr_file_p++;
  268.         }
  269.         
  270.     // skip // comments
  271.         if (c=='/' && pr_file_p[1] == '/')
  272.         {
  273.             while (*pr_file_p && *pr_file_p != '\n')
  274.                 pr_file_p++;
  275.             PR_NewLine();
  276.             pr_file_p++;
  277.             continue;
  278.         }
  279.         
  280.     // skip /* */ comments
  281.         if (c=='/' && pr_file_p[1] == '*')
  282.         {
  283.             do
  284.             {
  285.                 pr_file_p++;
  286.                 if (pr_file_p[0]=='\n')
  287.                     PR_NewLine();
  288.                 if (pr_file_p[1] == 0)
  289.                     return;
  290.             } while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
  291.             pr_file_p++;
  292.             continue;
  293.         }
  294.         
  295.         break;        // a real character has been found
  296.     }
  297. }
  298.  
  299. //============================================================================
  300.  
  301. #define    MAX_FRAMES    256
  302.  
  303. char    pr_framemacros[MAX_FRAMES][16];
  304. int        pr_nummacros;
  305.  
  306. void PR_ClearGrabMacros (void)
  307. {
  308.     pr_nummacros = 0;
  309. }
  310.  
  311. void PR_FindMacro (void)
  312. {
  313.     int        i;
  314.     
  315.     for (i=0 ; i<pr_nummacros ; i++)
  316.         if (!strcmp (pr_token, pr_framemacros[i]))
  317.         {
  318.             sprintf (pr_token,"%d", i);
  319.             pr_token_type = tt_immediate;
  320.             pr_immediate_type = &type_float;
  321.             pr_immediate._float = i;
  322.             return;
  323.         }
  324.     PR_ParseError ("Unknown frame macro $%s", pr_token);
  325. }
  326.  
  327. // just parses text, returning false if an eol is reached
  328. boolean PR_SimpleGetToken (void)
  329. {
  330.     int        c;
  331.     int        i;
  332.     
  333. // skip whitespace
  334.     while ( (c = *pr_file_p) <= ' ')
  335.     {
  336.         if (c=='\n' || c == 0)
  337.             return false;
  338.         pr_file_p++;
  339.     }
  340.     
  341.     i = 0;
  342.     while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';')
  343.     {
  344.         pr_token[i] = c;
  345.         i++;
  346.         pr_file_p++;
  347.     }
  348.     pr_token[i] = 0;
  349.     return true;
  350. }
  351.  
  352. void PR_ParseFrame (void)
  353. {
  354.     while (PR_SimpleGetToken ())
  355.     {
  356.         strcpy (pr_framemacros[pr_nummacros], pr_token);
  357.         pr_nummacros++;
  358.     }
  359. }
  360.  
  361. /*
  362. ==============
  363. PR_LexGrab
  364.  
  365. Deals with counting sequence numbers and replacing frame macros
  366. ==============
  367. */
  368. void PR_LexGrab (void)
  369. {    
  370.     pr_file_p++;    // skip the $
  371.     if (!PR_SimpleGetToken ())
  372.         PR_ParseError ("hanging $");
  373.     
  374. // check for $frame
  375.     if (!strcmp (pr_token, "frame"))
  376.     {
  377.         PR_ParseFrame ();
  378.         PR_Lex ();
  379.     }
  380. // ignore other known $commands
  381.     else if (!strcmp (pr_token, "cd")
  382.     || !strcmp (pr_token, "origin")
  383.     || !strcmp (pr_token, "base")
  384.     || !strcmp (pr_token, "flags")
  385.     || !strcmp (pr_token, "scale")
  386.     || !strcmp (pr_token, "skin") )
  387.     {    // skip to end of line
  388.         while (PR_SimpleGetToken ())
  389.         ;
  390.         PR_Lex ();
  391.     }
  392. // look for a frame name macro
  393.     else
  394.         PR_FindMacro ();
  395. }
  396.  
  397. //============================================================================
  398.  
  399. /*
  400. ==============
  401. PR_Lex
  402.  
  403. Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
  404. ==============
  405. */
  406. void PR_Lex (void)
  407. {
  408.     int        c;
  409.  
  410.     pr_token[0] = 0;
  411.     
  412.     if (!pr_file_p)
  413.     {
  414.         pr_token_type = tt_eof;
  415.         return;
  416.     }
  417.  
  418.     PR_LexWhitespace ();
  419.  
  420.     c = *pr_file_p;
  421.         
  422.     if (!c)
  423.     {
  424.         pr_token_type = tt_eof;
  425.         return;
  426.     }
  427.  
  428. // handle quoted strings as a unit
  429.     if (c == '\"')
  430.     {
  431.         PR_LexString ();
  432.         return;
  433.     }
  434.  
  435. // handle quoted vectors as a unit
  436.     if (c == '\'')
  437.     {
  438.         PR_LexVector ();
  439.         return;
  440.     }
  441.  
  442. // if the first character is a valid identifier, parse until a non-id
  443. // character is reached
  444.     if ( (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
  445.     {
  446.         pr_token_type = tt_immediate;
  447.         pr_immediate_type = &type_float;
  448.         pr_immediate._float = PR_LexNumber ();
  449.         return;
  450.     }
  451.     
  452.     if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
  453.     {
  454.         PR_LexName ();
  455.         return;
  456.     }
  457.     
  458.     if (c == '$')
  459.     {
  460.         PR_LexGrab ();
  461.         return;
  462.     }
  463.     
  464. // parse symbol strings until a non-symbol is found
  465.     PR_LexPunctuation ();
  466. }
  467.  
  468. //=============================================================================
  469.  
  470. /*
  471. ============
  472. PR_ParseError
  473.  
  474. Aborts the current file load
  475. ============
  476. */
  477. void PR_ParseError (char *error, ...)
  478. {
  479.     va_list        argptr;
  480.     char        string[1024];
  481.  
  482.     va_start (argptr,error);
  483.     vsprintf (string,error,argptr);
  484.     va_end (argptr);
  485.  
  486.     printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
  487.     
  488.     longjmp (pr_parse_abort, 1);
  489. }
  490.  
  491.  
  492. /*
  493. =============
  494. PR_Expect
  495.  
  496. Issues an error if the current token isn't equal to string
  497. Gets the next token
  498. =============
  499. */
  500. void PR_Expect (char *string)
  501. {
  502.     if (strcmp (string, pr_token))
  503.         PR_ParseError ("expected %s, found %s",string, pr_token);
  504.     PR_Lex ();
  505. }
  506.  
  507.  
  508. /*
  509. =============
  510. PR_Check
  511.  
  512. Returns true and gets the next token if the current token equals string
  513. Returns false and does nothing otherwise
  514. =============
  515. */
  516. boolean PR_Check (char *string)
  517. {
  518.     if (strcmp (string, pr_token))
  519.         return false;
  520.         
  521.     PR_Lex ();
  522.     return true;
  523. }
  524.  
  525. /*
  526. ============
  527. PR_ParseName
  528.  
  529. Checks to see if the current token is a valid name
  530. ============
  531. */
  532. char *PR_ParseName (void)
  533. {
  534.     static char    ident[MAX_NAME];
  535.     
  536.     if (pr_token_type != tt_name)
  537.         PR_ParseError ("not a name");
  538.     if (strlen(pr_token) >= MAX_NAME-1)
  539.         PR_ParseError ("name too long");
  540.     strcpy (ident, pr_token);
  541.     PR_Lex ();
  542.     
  543.     return ident;
  544. }
  545.  
  546. /*
  547. ============
  548. PR_FindType
  549.  
  550. Returns a preexisting complex type that matches the parm, or allocates
  551. a new one and copies it out.
  552. ============
  553. */
  554. type_t *PR_FindType (type_t *type)
  555. {
  556.     def_t    *def;
  557.     type_t    *check;
  558.     int        i;
  559.     
  560.     for (check = pr.types ; check ; check = check->next)
  561.     {
  562.         if (check->type != type->type
  563.         || check->aux_type != type->aux_type
  564.         || check->num_parms != type->num_parms)
  565.             continue;
  566.     
  567.         for (i=0 ; i< type->num_parms ; i++)
  568.             if (check->parm_types[i] != type->parm_types[i])
  569.                 break;
  570.             
  571.         if (i == type->num_parms)
  572.             return check;    
  573.     }
  574.     
  575. // allocate a new one
  576.     check = malloc (sizeof (*check));
  577.     *check = *type;
  578.     check->next = pr.types;
  579.     pr.types = check;
  580.     
  581. // allocate a generic def for the type, so fields can reference it
  582.     def = malloc (sizeof(def_t));
  583.     def->name = "COMPLEX TYPE";
  584.     def->type = check;
  585.     check->def = def;
  586.     return check;
  587. }
  588.  
  589.  
  590. /*
  591. ============
  592. PR_SkipToSemicolon
  593.  
  594. For error recovery, also pops out of nested braces
  595. ============
  596. */
  597. void PR_SkipToSemicolon (void)
  598. {
  599.     do
  600.     {
  601.         if (!pr_bracelevel && PR_Check (";"))
  602.             return;
  603.         PR_Lex ();
  604.     } while (pr_token[0]);    // eof will return a null token
  605. }
  606.  
  607.  
  608. /*
  609. ============
  610. PR_ParseType
  611.  
  612. Parses a variable type, including field and functions types
  613. ============
  614. */
  615. char    pr_parm_names[MAX_PARMS][MAX_NAME];
  616.  
  617. type_t *PR_ParseType (void)
  618. {
  619.     type_t    new;
  620.     type_t    *type;
  621.     char    *name;
  622.     
  623.     if (PR_Check ("."))
  624.     {
  625.         memset (&new, 0, sizeof(new));
  626.         new.type = ev_field;
  627.         new.aux_type = PR_ParseType ();
  628.         return PR_FindType (&new);
  629.     }
  630.     
  631.     if (!strcmp (pr_token, "float") )
  632.         type = &type_float;
  633.     else if (!strcmp (pr_token, "vector") )
  634.         type = &type_vector;
  635.     else if (!strcmp (pr_token, "float") )
  636.         type = &type_float;
  637.     else if (!strcmp (pr_token, "entity") )
  638.         type = &type_entity;
  639.     else if (!strcmp (pr_token, "string") )
  640.         type = &type_string;
  641.     else if (!strcmp (pr_token, "void") )
  642.         type = &type_void;
  643.     else
  644.     {
  645.         PR_ParseError ("\"%s\" is not a type", pr_token);
  646.         type = &type_float;    // shut up compiler warning
  647.     }
  648.     PR_Lex ();
  649.     
  650.     if (!PR_Check ("("))
  651.         return type;
  652.     
  653. // function type
  654.     memset (&new, 0, sizeof(new));
  655.     new.type = ev_function;
  656.     new.aux_type = type;    // return type
  657.     new.num_parms = 0;
  658.     if (!PR_Check (")"))
  659.     {
  660.         if (PR_Check ("..."))
  661.             new.num_parms = -1;    // variable args
  662.         else
  663.             do
  664.             {
  665.                 type = PR_ParseType ();
  666.                 name = PR_ParseName ();
  667.                 strcpy (pr_parm_names[new.num_parms], name);
  668.                 new.parm_types[new.num_parms] = type;
  669.                 new.num_parms++;
  670.             } while (PR_Check (","));
  671.     
  672.         PR_Expect (")");
  673.     }
  674.     
  675.     return PR_FindType (&new);
  676. }
  677.  
  678.